查看原文
其他

希望一个数据同步,包治百病

小姐姐养的狗 小姐姐味道 2019-12-12

哎!这是一个脏活,而且是个高风险的活。

大多数情况下,应用架构设计不好,引入什么新存储,引入什么DDD,治标不治本,都是扯淡。

但万一灵验呢?这就是数据同步的需求基础。且看下面需求场景。

应用场景

  • 业务数据发展到一定水平,需要将大部分冷热数据从熟悉的DB迁移到其他存储进行复杂查询和分析

  • 分库分表后,某些报表类查询无法工作,需要汇总到单库表进行操作

  • 分库分表有多个维度,需要拷贝多份数据达成冗余

  • 通过伪数据共享(没办法引入MQ、无法共享库表)进行业务改造

  • 慢存储→Cache之间的同步

  • 不停服数据迁移/scheme变更

  • 导数据导数据

  • 归档

很多时候,DataBus提供的仅仅是一个工具集。要完成最终的功能,大多数需要引入其他组件,如MQ、JOB等进行配合。同时,大部分数据同步工具需要有规范的数据库支持。所以,在忙着进行数据同步之前,需要对遗留数据进行一次集中数据治理。

一般数据同步,可以应用驱动双写:应用层同时向数据库或者多个存储写数据。因为代码在自己手中,这种方式在直觉上是简单可控的。但它引入的一致性问题将会是非常大的减分,因为没有复杂的协调协议(比如两阶段提交协议或者paxos算法),当出现问题时,很难保证多个存储处于相同的锁定状态。两个系统需要精确完成同样的写操作,并以同样的顺序完成序列化。如果写操作是有条件的或是有部分更新的语义,那么事情就会变得更麻烦。

基于数据库日志:将数据库作为唯一真实数据来源,并将变更从事务或提交日志中提取出来。这可以解决一致性问题,但是很难实现,MySQL这样的数据库有私有的交易日志格式和复制冗余解决方案,难以保证版本升级之后的可用性。由于要解决的是处理应用代码发起的数据变更,然后写入到另一个数据库中,冗余系统就得是用户层面的,而且要与来源无关。对于快速变化的技术公司,这种与数据来源的独立性非常重要,可以避免应用栈的技术锁定,或是绑死在二进制格式上。


数据同步方式

目前的数据同步解决方案,大体有以下三种:

  • 针对特定AB方数据同步进行的私有定制,如trigger

  • binlogwal日志级别的精确数据同步

  • 基于lastUpdateTime的查询结果集数据同步

针对于数据同步方式,有增量和全量同步两种:

  • 全量 一次性导出倒入完毕

  • 增量 数据随到随倒,小溪汇大海~


数据同步考虑的因素

基本特性

  • 同机房同步实时性(RTT)

  • 增量同步/全量同步策略

  • 事务支持粒度

  • 峰值应对策略 (消峰降级、延迟写入、扩容策略)

多机房(X一般公司不到这水平)

  • 数据库异地灾备

  • 多机房同步延迟

  • 机房切换(单元化切流/全站切流)

  • 数据对其方案

  • 双活

AB端数量和质量

  • 支持常见的SQL,如MySQLPostgres

  • 其他AB端支持,如:RedisMongoES

  • 数据同步的

  • 扩展方式和社区活跃度

高吞吐、低延迟

  • 并行化(并行读、并行写)

  • 顺序场景串行化

高可用

  • 监控、故障恢复

  • A(源端)端故障感知

  • B (目的端)端故障感知

  • 主从切换(或为对等节点)

  • 支持服务演练

  • 动态配置、故障重启

数据完整性

  • 较高的SLA高可用服务水准

  • 故障数据有回放机制和降级策略

  • A/B端数据自动校验功能(一致性验证)

其他

  • 数据过滤机制

  • 学习、部署成本

  • 硬件成本

实现

我们从几个典型实现、来看一下数据同步的复杂性。阿里在数据同步上可谓吓足了功夫,如:datax(ETL工具)、canal、otter、drc、dts、drds愚公精卫等。其中,使用最广泛的就是canal和datax。
另外,还有一些其他较活跃的工具,如sqoop、Maxwell  、debezium等

基于数据库的组件,一般都是伪装成一个DB的从库接收一份数据,剩下的都是框架内玩的事情了。如MySQL一般使用基于row的binlogpostgres基于wal日志进行复制。以MySQL为例、如果通过Binlog方式,将数据同步到ESHbase等其他盲区,就需要手写大量代码,包括组装数据、批量、顺序、HA等等很多场景都需要考虑。

我们限定一下一个最简单的使用场景,然后追踪在其上需要哪些工作量,又有哪些优缺点。场景如下:
将MySQL数据库的数据,同步一份数据到Postgres

Canal

最新的Canal已经支持MQ

如上图,除了需要搭建canal服务,将其伪装成一个slave,然后通过zookeeper做HA。我们还需要编码一个Canal Client服务,用来读取和解析数据。更多的情况,可能要引进一个MQ组件,用来缓解Canal的压力并承担一些扩展性功能。

一些限制

  • Canal源端只支持MySQL,并且只支持基于ROW模式的同步复制

  • 同步的表必须要有主键,无主键表update会是一个全表扫描 ,如果出现重复记录的话,同步会导致数据错乱

  • 支持部分ddl同步,ddl语句不支持幂等性操作,所以出现重复同步时,会导致同步挂起,可通过配置高级参数:跳过ddl异常,来解决这个问题(支持create table / drop table / alter table / truncate table / rename table / create index / drop index,其他类型的暂不支持,比如grant,create user,trigger等等)

  • 不支持带外键的记录同步

  • 数据库慎用或者禁用trigger

  • Canal是吃内存的,注意内存相关的调优

  • 堆积能力有限,这也是外部MQ的优势

maxwell

maxwell干脆就将这个过程更近了一步:直接将binlog解析成json存储在kafka中。用户使用的时候,直接订阅kafkatopic即可。

数据可能长这样:

mysql> update test.maxwell set daemon = 'firebus! firebus!' where id = 1;
maxwell: {
"database": "test",
"table": "maxwell",
"type": "update",
"ts": 1449786341,
"xid": 940786,
"commit": true,
"data": {"id":1, "daemon": "Firebus! Firebus!"},
"old": {"daemon": "Stanislaw Lem"}
}

maxwell为用户提供了默认的解决方式,需要额外引入kafka组件,这也是大部分数据分发共享的思路。由其github star数看来,要小canal一个数量级。在此基础上,有类似bireme更专某个场景的产品,不过都偏小众。

debezium

我觉得有必要提一下debezium。随着postgres的性能和特性越来越强,国内采用PG的公司逐渐增多。像这种场景,canal就无能为力了,debezium同时支持源端MySQLPostgresMongoDB,值得一试。同maxwell类似,同样需要kafka的支持。
缺点也是显而易见的,文档的质量不高,实践资料太少。

DataBus

Linkedin开源作品。Databus支持多种数据来源的变更抓取,包括OracleMySQL。是一个低延迟、可靠的、支持事务的、保持一致性的数据变更抓取系统
大同小异,databus在MySQL的处理方式上,也是通过解析binlog的方式进行数据抓取。使用MySQL Binlog解析库,我们也可以构造一个自己的数据同步中间件。DataBus做了更多的缓冲区relay、事件优化和回溯处理。在整个技术架构中,可以充当数据总线的作用。

DataX

Databus类似,DataX是一个在异构的数据库/文件系统之间高速交换数据的工具,实现了在任意的数据处理系统之间的数据交换,更像是一个ETL工具。
DataX支持的AB端数据源非常丰富,但因为它使用的定时抓取的方式,其延迟相比较Canal等基于日志的方式,是比较大的。同时,DataX对数据的要求较高,比如你的数据库如果没有最后更新时间之类的字段,从源端读取变更数据将有一定的困难。

总结

整体而言,CanalDataXDataBus的使用人数多,社区活跃,框架也比较成熟。在满足应用场景的前提下,优先选择,它们都有自己的HA方案,代价适中。

CanalDataBus源端支持类型有限,但延迟低,需要手写Client来处理数据。大多数情况下需要加入MQ进行配合。

DataX支持丰富,使用简单,但延迟较大(依赖获取频率),只需要手写规则文件,对复杂同步自定义性不强。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存